package com.hmkj.core.service.user.impl;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hmkj.common.baseMapper.GenericMapper;
import com.hmkj.common.entity.dtgrid.DtGrid;
import com.hmkj.common.entity.dtgrid.QueryUtils;
import com.hmkj.common.utils.DateUtils;
import com.hmkj.common.utils.JsonUtils;
import com.hmkj.common.utils.StringUtils;
import com.hmkj.core.constant.ConfigNID;
import com.hmkj.core.constant.PointNid;
import com.hmkj.core.constant.SessionId;
import com.hmkj.core.exception.BussinessException;
import com.hmkj.core.exception.DtGridException;
import com.hmkj.core.mapper.amount.AccountMapper;
import com.hmkj.core.mapper.amount.AccountSimulateMapper;
import com.hmkj.core.mapper.amount.RechargeMapper;
import com.hmkj.core.mapper.operate.AgentMapper;
import com.hmkj.core.mapper.user.UserFreezeMapper;
import com.hmkj.core.mapper.user.UserMapper;
import com.hmkj.core.model.amount.RechargeModel;
import com.hmkj.core.model.user.UserModel;
import com.hmkj.core.po.amount.Account;
import com.hmkj.core.po.amount.AccountSimulate;
import com.hmkj.core.po.amount.Recharge;
import com.hmkj.core.po.operate.Agent;
import com.hmkj.core.po.user.User;
import com.hmkj.core.po.user.UserFreeze;
import com.hmkj.core.service.cache.RedisService;
import com.hmkj.core.service.cache.SessionService;
import com.hmkj.core.service.operate.PointRuleService;
import com.hmkj.core.service.user.UserService;
import com.xiaoleilu.hutool.date.DateUtil;
import com.xiaoleilu.hutool.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 用户业务相关Service接口实现<br>
 *
 * @author donfy
 * @ClassName: UserServiceImpl
 * @date 2017-08-15 03:03:30
 */
@Slf4j
@Service
@Scope("prototype")
@Transactional(rollbackFor = Exception.class)
public class UserServiceImpl implements UserService {

    @Resource
    private UserMapper userMapper;
    @Resource
    private AccountMapper accountMapper;
    @Resource
    private SessionService sessionService;
    @Resource
    private AgentMapper agentMapper;
    @Resource
    private UserFreezeMapper userFreezeMapper;
    @Resource
    private RechargeMapper rechargeMapper;
    @Resource
    private PointRuleService pointRuleService;
    @Resource
    private AccountSimulateMapper accountSimulateMapper;
    @Resource
    private RedisService redisService;

    @Override
    public GenericMapper<User, Integer> _getMapper() {
        return userMapper;
    }

    @Override
    public void doRegister(final UserModel userModel) {
        log.info("注册service");
        userModel.checkRegister();
        // 校验手机号是否被注册
        if (userMapper.selectCount(new User(u -> u.setMobile(userModel.getMobile()))) > 0)
            throw new BussinessException("当前手机号已被注册");
        User uSave = new User();
        uSave.setMobile(userModel.getMobile());
        uSave.setSource(userModel.getSource());
        // 初始化层级code,初始化代理商信息
        if (userModel.getParentId() == null) {
            Integer pc = userMapper.countTopByLevel();
            uSave.setCode((pc + 1) + "");
            uSave.setLevel(1);
            uSave.setRewardScale(redisService.get(ConfigNID.REWARD_SCALES_DEFAULT, BigDecimal.class));
            Agent agent = agentMapper.selectOne(new Agent(t -> {
                t.setDomain(userModel.getSource());
                t.setStatus(Agent.STATUS.T1.code);
                t.setDelFlag(Agent.DELFLAG.NORMAL.code);
            }));
            if (agent == null) throw new BussinessException("查询代理商是失败");
            uSave.setAgentId(agent.getId());
        } else {// 有父级
            final User parent = userMapper.selectByPrimaryKey(userModel.getParentId());
            Integer pc = countPartnerByLevel(parent.getCode(), parent.getLevel());
            uSave.setCode(parent.getCode() + "." + (pc + 1));
            uSave.setLevel(parent.getLevel() == null ? 1 : parent.getLevel() + 1);
            uSave.setParentId(parent.getId());
            uSave.setAgentId(parent.getAgentId());
            uSave.setSource(parent.getSource());
        }
        // 解密密码并md5加密保存
        uSave.setPassword(userModel.encodePwd(userModel.decryptPwd()));
        String mobilePhone = userModel.getMobile();
        uSave.setUserName(StrUtil.sub(mobilePhone, 0, 2) + "****" + StrUtil.sub(mobilePhone, 9, mobilePhone.length()));
        userMapper.insert(uSave);
        final User user = userMapper.selectOne(new User(u -> u.setMobile(userModel.getMobile())));
        // 初始化邀请码
        userMapper.updateByPrimaryKeySelective(new User(u -> {
            u.setId(user.getId());
            u.setInviteCode(producesInviteCode(user.getId()));
        }));
        // 初始化 account 账户
        accountMapper.insert(new Account(a -> a.setUserId(user.getId())));
        // 初始化 accountSimulate 账户
        BigDecimal amount = redisService.get(ConfigNID.ACCOUNT_SIM_AMOUNT, BigDecimal.class);
        if (amount == null) {
            throw new BussinessException("获取初始模拟账户金额失败");
        }
        accountSimulateMapper.insert(new AccountSimulate(a -> {
            a.setUserId(user.getId());
            a.setTotal(amount);
            a.setAvailable(amount);
            a.setFreeze(BigDecimal.ZERO);
        }));
        // 初始化用户冻结表
        userFreezeMapper.insert(new UserFreeze(t -> t.setUserId(user.getId())));

    }

    /**
     * 成员会员邀请码
     *
     * @param id
     * @return
     */
    private String producesInviteCode(Integer id) {
        String idStr = id.toString();
        int strLen = idStr.length();
        if (strLen < 3) {
            while (strLen < 3) {
                StringBuffer sb = new StringBuffer();
                sb.append("0").append(idStr);
                idStr = sb.toString();
                strLen = idStr.length();
            }
        }
        return "M" + idStr;
    }


    @Override
    public Integer countPartnerByLevel(String code, int level) {
        Map<String, Object> params = new HashMap<>();
        if (StringUtils.isBlank(code)) {
            params.put("level", 0);
            params.put("offset", 0);
            return userMapper.countPartnerByLevel(params);
        }

        params.put("code", code);
        if (level != 0) {
            // 计算偏移量（用户本身节点标识中的点的数量）
            int offset = code.length() - code.replace(".", "").length();
            params.put("level", level);
            params.put("offset", offset);
        }
        return userMapper.countPartnerByLevel(params);
    }

    /**
     * 分页查询普通对象, 使用该方法必须再mapper内重写findListBySqlJoin方法 否则报异常
     *
     * @param dtGridPager
     * @return
     * @throws DtGridException
     */
    @Override
    public DtGrid getDtGridForFriendsList(String dtGridPager) throws DtGridException {

        try {
            ObjectMapper mapper = new ObjectMapper();
            HashMap<String, String> hashMap = new HashMap<>();
            DtGrid dtGrid = mapper.readValue(dtGridPager, DtGrid.class);
            if (dtGrid.getNcColumnsType() != null && dtGrid.getNcColumnsType().size() > 0) {
                for (String key : dtGrid.getNcColumnsType().keySet()) {
                    for (int i = 0; i < dtGrid.getNcColumnsType().get(key).size(); i++) {
                        System.out.println();
                        hashMap.put((String) dtGrid.getNcColumnsType().get(key).get(i), key);
                    }
                    dtGrid.setNcColumnsTypeList(hashMap);
                }
            }
            // 表格查询参数处理
            QueryUtils.parseDtGridSql(dtGrid);
            // 获取查询条件Sql
            String whereSql = dtGrid.getWhereSql();
            // 获取排序Sql
//            String sortSql = dtGrid.getSortSql();

            Map<String, Object> params = new HashMap<>();
            params.put("whereSql", whereSql);
            long recordCount = userMapper.countForFriendsBySqlJoin(params);
            int pageSize = dtGrid.getPageSize();
            int pageNum = (int) recordCount / dtGrid.getPageSize() + (recordCount % dtGrid.getPageSize() > 0 ? 1 : 0);

            dtGrid.setPageCount(pageNum);
            dtGrid.setRecordCount(recordCount);

            params.put("nowPage", (dtGrid.getNowPage() - 1) * pageSize);
            params.put("pageSize", pageSize);

            List<UserModel> list = userMapper.findListForFriendsBySqlJoin(params);
            dtGrid.setExhibitDatas(JsonUtils.toGenericObject(JSON.toJSONString(list), new TypeReference<List<Object>>() {
            }));
            return dtGrid;
        } catch (Exception e) {
            e.printStackTrace();
            throw new DtGridException();
        }

    }

    @Override
    public long investorSum() throws Exception {
        Map<String, Object> params = new HashMap<>();
        String whereSql = " and t.type = 1 and t.del_flag =1";
        params.put("whereSql", whereSql);
        return userMapper.investorSum(params);
    }

    @Override
    public void updateUserToBandingMailbox(User user, String email) {
        updateByPrimaryKeySelective(new User(u -> {
            u.setId(user.getId());
            u.setEmail(email);
        }));
    }

    /**
     * 分页查询普通对象, 使用该方法必须再mapper内重写findListBySqlJoin方法 否则报异常
     *
     * @param dtGridPager
     * @return
     * @throws DtGridException
     */
    public DtGrid getDtGridListExport(String dtGridPager) throws DtGridException {
        try {
            ObjectMapper mapper = new ObjectMapper();
            DtGrid dtGrid = mapper.readValue(dtGridPager, DtGrid.class);
            // 默认导出当前页数据（不需要数据库查询），ExportAllData为TRUE导出所有数据（取数据库进行查询）
            if (dtGrid.getExportAllData()) {
                dtGrid.setNowPage(1);
                dtGrid.setPageSize(1000000);
                dtGridPager = mapper.writeValueAsString(dtGrid);
                dtGrid = getDtGridForFriendsList(dtGridPager);
                String dataJsonStr = JSON.toJSONString(dtGrid.getExhibitDatas());
                List<Map<String, Object>> exportDatas = mapper.readValue(dataJsonStr, new TypeReference<List<HashMap<String, Object>>>() {
                });
                dtGrid.setExportDatas(exportDatas);
            }
            return dtGrid;
        } catch (Exception e) {
            e.printStackTrace();
            throw new DtGridException();
        }
    }

    @Override
    public User selectByInviteCode(String inviteCode) {
        return userMapper.selectByInviteCode(inviteCode);
    }

    @Override
    public void updateUserMobile(Integer userId, String newUserMobilePhone) {
        int i = userMapper.selectCount(new User(u -> u.setMobile(newUserMobilePhone)));
        if (i != 0) throw new BussinessException("当前手机号已注册");
        int i2 = userMapper.updateByPrimaryKeySelective(new User(u -> {
            u.setId(userId);
            u.setMobile(newUserMobilePhone);
        }));
        if (i2 != 1) throw new BussinessException("修改失败");
    }

    @Override
    public User realName(final User user) {
        //校验身份证号码重复
        int m = userMapper.selectCount(new User(cpu -> {
            cpu.setIdCard(user.getIdCard());
            cpu.setDelFlag(UserModel.DELFLAG.NORMAL.code);
        }));
        if (m > 0) {
            throw new BussinessException("身份证号码已存在,请检查身份证号码是否正确");
        }
        String idc = user.getIdCard();
        String year = idc.substring(6,10);
        String month = idc.substring(10,12);
        String day = idc.substring(12,14);
        Date birthday =  DateUtils.valueOf( year+"-"+month+"-"+day);
        int i = userMapper.updateByPrimaryKeySelective(new User(u -> {
            u.setRealName(user.getRealName());
            u.setIdCard(user.getIdCard());
            u.setBirthday(birthday);
            u.setId(user.getId());
        }));
        if (i != 1) throw new BussinessException("实名认证提交失败");
        return userMapper.selectOne(user);
    }

    @Override
    public User bindAlipay(User user) {
        int i = userMapper.updateByPrimaryKeySelective(new User(u -> {
            u.setAlipayAccount(user.getAlipayAccount());
            u.setId(user.getId());
        }));
        if (i != 1) throw new BussinessException("绑定支付宝账户提交失败");
        return userMapper.selectOne(user);
    }

    @Override
    public User doLogin(final UserModel model, HttpServletRequest request) {
        final User user = userMapper.selectOne(new User(u -> u.setMobile(model.getMobile())));
        // 保存登录ip 最后登录时间
        userMapper.updateByPrimaryKeySelective(new User(u -> {
            u.setId(user.getId());
            u.setLastLoginDate(new Date());
            u.setLastLoginIp(model.getLastLoginIp());
        }));
        // 登录动作
        String sessionId = sessionService.setSession(SessionId.MEMBER_USER, user, request);
        userMapper.updateByPrimaryKeySelective(new User(u -> {
            u.setId(user.getId());
            u.setHid(sessionId);
        }));
        return user;
    }

    @Override
    public long inviteNumber(Integer userId) {
        List<User> users = userMapper.select(new User(user -> {
            user.setParentId(userId);
        }));
        if (users != null && users.size() > 0) {
            return (long) users.size();
        } else {
            return 0;
        }
    }

    @Override
    public DtGrid getDtGridModelList(DtGrid dtGrid) throws DtGridException {
        try {
            ObjectMapper mapper = new ObjectMapper();
            HashMap<String, String> hashMap = new HashMap<>();
            if (dtGrid.getNcColumnsType() != null && dtGrid.getNcColumnsType().size() > 0) {
                for (String key : dtGrid.getNcColumnsType().keySet()) {
                    for (int i = 0; i < dtGrid.getNcColumnsType().get(key).size(); i++) {
                        System.out.println();
                        hashMap.put((String) dtGrid.getNcColumnsType().get(key).get(i), key);
                    }
                    dtGrid.setNcColumnsTypeList(hashMap);
                }
            }
            // 表格查询参数处理
            QueryUtils.parseDtGridSql(dtGrid);
            // 获取查询条件Sql
            String whereSql = dtGrid.getWhereSql();
            // 获取排序Sql
            String sortSql = dtGrid.getSortSql();


            Map<String, Object> params = new HashMap<>();
            whereSql = whereSql + " group by date_format(t.create_time, '%Y-%m-%d')";
            params.put("whereSql", whereSql);
            params.put("sortSql", sortSql);
            long recordCount = userMapper.countModelBySqlJoin(params);
            int pageSize = dtGrid.getPageSize();
            int pageNum = (int) recordCount / dtGrid.getPageSize() + (recordCount % dtGrid.getPageSize() > 0 ? 1 : 0);

            dtGrid.setPageCount(pageNum);
            dtGrid.setRecordCount(recordCount);

            params.put("nowPage", (dtGrid.getNowPage() - 1) * pageSize);
            params.put("pageSize", pageSize);
            List<UserModel> list = userMapper.findModelListBySqlJoin(params);
            if (list != null && list.size() > 0) {
                list.forEach(userModel -> {
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                    String whereSql1 = "AND t.del_flag = " + Recharge.DELFLAG.NORMAL.code + " AND  t.status = " + Recharge.STATUS.T3.code + " AND t.create_time >= '" + sdf.format(userModel.getRegisterTime()) + " 00:00:00' AND t.create_time < '" + sdf.format(userModel.getRegisterTime()) + " 23:59:59' GROUP BY t.user_id ";
                    Map<String, Object> param = new HashMap<>();
                    param.put("whereSql", whereSql1);
                    RechargeModel rechargeModel = rechargeMapper.selectNumByTime(param);
                    if (rechargeModel != null) {
                        if (rechargeModel.getRechargeNum() != null) {
                            userModel.setRechargeNum(rechargeModel.getRechargeNum());
                            BigDecimal recBd = BigDecimal.valueOf(rechargeModel.getRechargeNum());
                            BigDecimal userBd = BigDecimal.valueOf(userModel.getUserNum());
                            userModel.setScaleRec(recBd.divide(userBd, 2, BigDecimal.ROUND_HALF_UP));
                        } else {
                            userModel.setRechargeNum((long) 0);
                            userModel.setScaleRec(BigDecimal.ZERO);
                        }
                        if (rechargeModel.getTotalAmo() != null) {
                            userModel.setTotalAmo(rechargeModel.getTotalAmo());
                            BigDecimal recBd = BigDecimal.valueOf(rechargeModel.getRechargeNum());
                            userModel.setAverageAmo(rechargeModel.getTotalAmo().divide(recBd, 2, BigDecimal.ROUND_HALF_UP));
                        } else {
                            userModel.setTotalAmo(BigDecimal.ZERO);
                            userModel.setAverageAmo(BigDecimal.ZERO);
                        }
                    } else {
                        userModel.setRechargeNum((long) 0);
                        userModel.setScaleRec(BigDecimal.ZERO);
                        userModel.setTotalAmo(BigDecimal.ZERO);
                        userModel.setAverageAmo(BigDecimal.ZERO);
                    }
                });
            }
            dtGrid.setExhibitDatas(JsonUtils.toGenericObject(JSON.toJSONString(list), new TypeReference<List<Object>>() {
            }));
            return dtGrid;
        } catch (Exception e) {
            e.printStackTrace();
            throw new DtGridException();
        }
    }

    @Override
    public List<String> getSource() {
        Map<String, Object> params = new HashMap<>();
        params.put("type", User.TYPE.T1.code);
        params.put("delFlag", User.DELFLAG.NORMAL.code);
        List<String> sources = userMapper.getSource(params);
        return sources;
    }

    @Override
    public void doSign(Integer id) {
        User user = userMapper.selectByPrimaryKey(id);
        if (null == user) throw new BussinessException("用户不存在");
        String now = DateUtil.format(new Date(), "yyyyMMdd");
        if (user.getLastSignDate() == null || !now.equals(DateUtil.format(user.getLastSignDate(), "yyyyMMdd"))) {
            // 今日未签到
            if (userMapper.updateByIdAndVersionSelective(new User(t -> {
                t.setId(user.getId());
                t.setVersion(user.getVersion());
                t.setLastSignDate(new Date());
            })) != 1) throw new BussinessException("更新签到时间失败");

            // 发送签到积分
            pointRuleService.sendPoint(user.getId(), PointNid.T2);
        } else {
            throw new BussinessException("今日已签到");
        }
    }

    @Override
    public List<User> selectOffline(Integer parentId) {
        return userMapper.selectOffline(parentId);
    }

    @Override
    public DtGrid getDtGridModelListExport(String dtGridPager) throws DtGridException {
        try {
            ObjectMapper mapper = new ObjectMapper();
            DtGrid dtGrid = mapper.readValue(dtGridPager, DtGrid.class);
            // 默认导出当前页数据（不需要数据库查询），ExportAllData为TRUE导出所有数据（取数据库进行查询）
            if (dtGrid.getExportAllData()) {
                dtGrid.setNowPage(1);
                dtGrid.setPageSize(1000000);
                dtGrid = getDtGridModelList(dtGrid);
                String dataJsonStr = JSON.toJSONString(dtGrid.getExhibitDatas());
                List<Map<String, Object>> exportDatas = mapper.readValue(dataJsonStr, new TypeReference<List<HashMap<String, Object>>>() {
                });
                dtGrid.setExportDatas(exportDatas);
            }
            return dtGrid;
        } catch (Exception e) {
            e.printStackTrace();
            throw new DtGridException();
        }
    }

}
